/*
尽可能还原 Promise 中的每一个 API, 并通过注释的方式描述思路和原理.
*/

// 声明promise状态常量
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
class MyPromise {

    // 初始化状态和值属性 
    promiseStatus = PENDING;
    promiseResult = null;

    // 保存成功和失败的回调函数，可能有多个回调函数
    onResolvedCallbacks = [];
    onRejectedCallbacks = [];
    // 接受一个执行器函数executor，并在创建的时候同步执行
    constructor(executor) {
        // 执行器函数需要两个参数 resolve、reject
        try {
            executor(this.resolve, this.reject);
        } catch (e) {
            this.reject(e)
        }
    }

    // 声明resolve函数，使用箭头函数保准this指向 promise 对象， reject 函数同此
    // resolve 函数接受一个参数为成功的结果，并改变promise的状态，reject 函数同此
    resolve = (value) => {
        // 判断状态
        if (this.promiseStatus !== PENDING) return;
        this.promiseStatus = FULFILLED;
        this.promiseResult = value;
        // 异步情况下执行回调函数处理, 考虑多个回调函数的情况
        while (this.onResolvedCallbacks.length) {
            this.onResolvedCallbacks.shift()();
        }
    }
    // 声明reject函数，接受一个参数为失败的理由
    reject = (reason) => {
        if (this.promiseStatus !== PENDING) return;
        this.promiseStatus = REJECTED;
        this.promiseResult = reason;
        while (this.onRejectedCallbacks.length) {
            this.onRejectedCallbacks.shift()();
        }
    }

    // then 方法接受两个回调函数参数对成功或失败的情况进行处理
    then(onResolved, onRejected) {

        // 参数判断
        onResolved = onResolved && typeof onResolved === 'function' ? onResolved : value => value;
        onRejected = onRejected && typeof onRejected === 'function' ? onRejected : reason => {
            throw reason
        };

        // 需要判断返回自身的情况
        let promise = new MyPromise((resolve, reject) => {
            // 判断成功或是失败或待定
            if (this.promiseStatus === FULFILLED) {
                // 异步操作, 下同
                setTimeout(() => {
                    // 处理抛出错误的情况, 下同
                    try {
                        let res = onResolved(this.promiseResult);
                        resolvePromise(promise, res, resolve, reject);
                    } catch (e) {
                        reject(e)
                    }
                }, 0);
            } else if (this.promiseStatus === REJECTED) {
                setTimeout(() => {
                    try {
                        let res = onRejected(this.promiseResult);
                        resolvePromise(promise, res, resolve, reject);
                    } catch (e) {
                        reject(e)
                    }
                }, 0);
            } else {
                // 异步情况下返回待定状态，需要保存回调函数，待状态改变时再调用
                this.onResolvedCallbacks.push(() => {
                    setTimeout(() => {
                        try {
                            let res = onResolved(this.promiseResult);
                            resolvePromise(promise, res, resolve, reject);
                        } catch (e) {
                            reject(e)
                        }
                    }, 0);
                });
                this.onRejectedCallbacks.push(() => {
                    setTimeout(() => {
                        try {
                            let res = onRejected(this.promiseResult);
                            resolvePromise(promise, res, resolve, reject);
                        } catch (e) {
                            reject(e)
                        }
                    }, 0);
                });
            }
        })

        function resolvePromise(promise, res, resolve, reject) {
            // promise 对象自返回时报错
            if (promise === res) {
                return reject(new TypeError('Chaining cycle detected for promise #<Promise>').message);
            }
            if (res instanceof MyPromise) {
                // res为promise实例对象
                res.then(value => {
                    resolve(value);
                }, reason => {
                    reject(reason);
                })
            } else {
                // 普通值返回resolve的结果
                resolve(res);
            }
        }

        return promise;
    }

    // catch
    catch(onRejected) {
        return this.then(undefined, onRejected);
    }

    // finally
    finally(onFinally) {
        return this.then(value => {
            return MyPromise.resolve(onFinally()).then(() => value);
        }, reason => {
            return MyPromise.resolve(onFinally()).then(() => {throw reason});
        })
    }

    // 静态方法
    static resolve(value) {
        if (value instanceof MyPromise) return value;
        return new MyPromise(resolve => resolve(value));
    }

    static reject(reason) {
        return new MyPromise(reject => reject(reason));
    }

    static all(arr) {
        let result = [];
        let index = 0;
        return new MyPromise((resolve, reject) => {
            for (let i = 0; i < arr.length; i++) {
                let current = arr[i];
                if (current instanceof MyPromise) {
                    current.then(value => {
                        result[i] = value;
                        index++;
                        if (index === arr.length) {
                            resolve(result)
                        }
                    }, reason => {
                        reject(reason);
                    })
                } else {
                    result[i] = current;
                    index++;
                    if (index === arr.length) {
                        resolve(result)
                    } 
                }
            }
        })
    }

    static race(arr) {
        return new MyPromise((resolve, reject) => {
            for (let i = 0; i < arr.length; i++) {
                arr[i].then(v => {
                    resolve(v);
                }, r => {
                    reject(r);
                })
            }
        })
    }
}